{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# geometry functions allow a ***design*** to be created more easily\n",
    "\n",
    "the geometry functions here allow points to be created (part I), measured (part II) and moved/copied (part III)\n",
    "\n",
    "geometry functions work best when x, y and z are all defined for all points\n",
    "\n",
    "'tau' (equal to 2*pi) is used throughout this notebook - see tau section of the [design tips notebook](https://colab.research.google.com/github/FullControlXYZ/fullcontrol/blob/master/tutorials/colab/design_tips_colab.ipynb) for further details\n",
    "\n",
    "<*this document is a jupyter notebook - if they're new to you, check out how they work:\n",
    "[link](https://www.google.com/search?q=ipynb+tutorial),\n",
    "[link](https://jupyter.org/try-jupyter/retro/notebooks/?path=notebooks/Intro.ipynb),\n",
    "[link](https://colab.research.google.com/)*>\n",
    "\n",
    "*run all cells in this notebook in order (keep pressing shift+enter)*"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if 'google.colab' in str(get_ipython()):\n  !pip install git+https://github.com/FullControlXYZ/fullcontrol --quiet\nimport fullcontrol as fc\n",
    "from math import tau, sin"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## I. create points\n",
    "\n",
    "single points:\n",
    "- points defined by polar coordinates\n",
    "- midpoint of two points\n",
    "\n",
    "lists of points:\n",
    "- arc\n",
    "- arc with variable radius\n",
    "- elliptical arc\n",
    "- rectangle\n",
    "- circle\n",
    "- polygon\n",
    "- spiral\n",
    "- helix (optionally with variable radius)\n",
    "- squarewave\n",
    "- segmented line"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### midpoint() and polar_to_point() (point defined by polar coordinates)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pt1 = fc.Point(x=0,y=0,z=0)\n",
    "pt2 = fc.Point(x=0,y=10,z=0)\n",
    "pt3 = fc.polar_to_point(pt2, 10, tau/8)\n",
    "pt4 = fc.midpoint(pt1, pt2)\n",
    "steps = [pt1, pt2, pt3, pt4]\n",
    "steps.append(fc.PlotAnnotation(point=pt4, label=\"midpoint between point 1 and point 2\"))\n",
    "steps.append(fc.PlotAnnotation(point=pt1, label=\"point 1\"))\n",
    "steps.append(fc.PlotAnnotation(point=pt2, label=\"point 2\"))\n",
    "steps.append(fc.PlotAnnotation(point=pt3, label=\"point defined by polar coordinates relative to point 2\"))\n",
    "fc.transform(steps, 'plot', fc.PlotControls(color_type='print_sequence', style='line'))"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### rectangle"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "start_point = fc.Point(x=10, y=10, z=0)\n",
    "x_size = 10\n",
    "y_size = 5\n",
    "clockwise = True\n",
    "steps = fc.rectangleXY(start_point, x_size, y_size, clockwise)\n",
    "steps.append(fc.PlotAnnotation(point=steps[-1], label=\"start/end\"))\n",
    "steps.append(fc.PlotAnnotation(point=steps[1], label=\"first point after start\"))\n",
    "fc.transform(steps, 'plot', fc.PlotControls(color_type='print_sequence', style='line'))"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### circle"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "centre_point = fc.Point(x=10, y=10, z=0)\n",
    "radius = 10\n",
    "start_angle = 0\n",
    "segments = 32\n",
    "clockwise = True\n",
    "steps = fc.circleXY(centre_point, radius, start_angle, segments, clockwise)\n",
    "steps.append(fc.PlotAnnotation(point=steps[-1], label=\"start/end\"))\n",
    "steps.append(fc.PlotAnnotation(point=steps[1], label=\"first point after start\"))\n",
    "steps.append(fc.PlotAnnotation(point=centre_point, label=\"centre\"))\n",
    "fc.transform(steps, 'plot', fc.PlotControls(color_type='print_sequence', style='line'))"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### ellipse"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "centre_point = fc.Point(x=10, y=10, z=0)\n",
    "a = 10\n",
    "b = 5\n",
    "start_angle = 0\n",
    "segments = 32\n",
    "clockwise = True\n",
    "steps = fc.ellipseXY(centre_point, a, b, start_angle, segments, clockwise)\n",
    "steps.append(fc.PlotAnnotation(point=steps[-1], label=\"start/end\"))\n",
    "steps.append(fc.PlotAnnotation(point=steps[1], label=\"first point after start\"))\n",
    "steps.append(fc.PlotAnnotation(point=centre_point, label=\"centre\"))\n",
    "fc.transform(steps, 'plot', fc.PlotControls(color_type='print_sequence', style='line'))"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### polygon"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "centre_point = fc.Point(x=10, y=10, z=0)\n",
    "enclosing_radius = 10\n",
    "start_angle = 0\n",
    "sides = 6\n",
    "clockwise = True\n",
    "steps = fc.polygonXY(centre_point, enclosing_radius, start_angle, sides, clockwise)\n",
    "steps.append(fc.PlotAnnotation(point=steps[-1], label=\"start/end\"))\n",
    "steps.append(fc.PlotAnnotation(point=steps[1], label=\"first point after start\"))\n",
    "steps.append(fc.PlotAnnotation(point=centre_point, label=\"centre\"))\n",
    "fc.transform(steps, 'plot', fc.PlotControls(color_type='print_sequence', style='line'))"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### arc"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "centre_point = fc.Point(x=10, y=10, z=0)\n",
    "radius = 10\n",
    "start_angle = 0\n",
    "arc_angle = 0.75*tau\n",
    "segments = 64\n",
    "steps = fc.arcXY(centre_point, radius, start_angle, arc_angle, segments)\n",
    "steps.append(fc.PlotAnnotation(point=steps[-1], label=\"end\"))\n",
    "steps.append(fc.PlotAnnotation(point=steps[0], label=\"start\"))\n",
    "steps.append(fc.PlotAnnotation(point=centre_point, label=\"centre\"))\n",
    "fc.transform(steps, 'plot', fc.PlotControls(color_type='print_sequence', style='line'))"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### variable arc"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "centre_point = fc.Point(x=10, y=10, z=0)\n",
    "radius = 10\n",
    "start_angle = 0\n",
    "arc_angle = 0.75*tau\n",
    "segments = 64\n",
    "radius_change = -6\n",
    "z_change = 0\n",
    "steps = fc.variable_arcXY(centre_point, radius, start_angle, arc_angle, segments, radius_change, z_change)\n",
    "steps.append(fc.PlotAnnotation(point=steps[-1], label=\"end\"))\n",
    "steps.append(fc.PlotAnnotation(point=steps[0], label=\"start\"))\n",
    "steps.append(fc.PlotAnnotation(point=centre_point, label=\"centre\"))\n",
    "fc.transform(steps, 'plot', fc.PlotControls(color_type='print_sequence', style='line'))"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### elliptical arc"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "centre_point = fc.Point(x=10, y=10, z=0)\n",
    "a = 10\n",
    "b = 5\n",
    "start_angle = 0\n",
    "arc_angle = 0.75*tau\n",
    "segments = 64\n",
    "steps = fc.elliptical_arcXY(centre_point, a, b, start_angle, arc_angle, segments)\n",
    "steps.append(fc.PlotAnnotation(point=steps[-1], label=\"end\"))\n",
    "steps.append(fc.PlotAnnotation(point=steps[0], label=\"start\"))\n",
    "steps.append(fc.PlotAnnotation(point=centre_point, label=\"centre\"))\n",
    "fc.transform(steps, 'plot', fc.PlotControls(color_type='print_sequence', style='line'))"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### spiral"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "centre_point = fc.Point(x=10, y=10, z=0)\n",
    "start_radius = 10\n",
    "end_radius = 8\n",
    "start_angle = 0\n",
    "n_turns = 5\n",
    "segments = 320\n",
    "z_change = 0\n",
    "clockwise = True\n",
    "steps = fc.spiralXY(centre_point, start_radius, end_radius, start_angle, n_turns, segments, clockwise)\n",
    "steps.append(fc.PlotAnnotation(point=steps[-1], label=\"end\"))\n",
    "steps.append(fc.PlotAnnotation(point=steps[0], label=\"start\"))\n",
    "steps.append(fc.PlotAnnotation(point=centre_point, label=\"centre\"))\n",
    "fc.transform(steps, 'plot', fc.PlotControls(color_type='print_sequence', style='line'))\n",
    "\n",
    "# spirals are also possible by using fc.variable_arcXY with 'arc_angle' set to the number of passes * tau and 'radius_change' set to the total change in radius over the whole spiral\n"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### helix"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "centre_point = fc.Point(x=10, y=10, z=0)\n",
    "start_radius = 10\n",
    "end_radius = 10\n",
    "start_angle = 0\n",
    "n_turns = 5\n",
    "pitch_z = 0.4\n",
    "segments = 320\n",
    "clockwise = True\n",
    "steps = fc.helixZ(centre_point, start_radius, end_radius, start_angle, n_turns, pitch_z, segments, clockwise)\n",
    "steps.append(fc.PlotAnnotation(point=steps[-1], label=\"end\"))\n",
    "steps.append(fc.PlotAnnotation(point=steps[0], label=\"start\"))\n",
    "steps.append(fc.PlotAnnotation(point=centre_point, label=\"centre\"))\n",
    "fc.transform(steps, 'plot', fc.PlotControls(color_type='print_sequence', style='line'))\n",
    "\n",
    "# helices are also possible by using fc.variable_arcXY with 'arc_angle' set to the number of passes * tau and 'z_change' set to the total helix length"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### waves"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# wave 1\n",
    "start_point = fc.Point(x=10, y=10, z=0)\n",
    "direction = fc.Vector(x=1,y=0)\n",
    "amplitude = 5\n",
    "line_spacing = 1\n",
    "periods = 10\n",
    "extra_half_period = False\n",
    "extra_end_line = False\n",
    "steps = fc.squarewaveXY(start_point, direction, amplitude, line_spacing, periods, extra_half_period, extra_end_line)\n",
    "steps.append(fc.PlotAnnotation(point=start_point, label=\"start of wave 1\"))\n",
    "\n",
    "# wave 2\n",
    "start_point = fc.Point(x=10, y=20, z=0)\n",
    "extra_half_period = True\n",
    "# steps.extend([fc.Extruder(on=False), start_point, fc.Extruder(on=True)])\n",
    "steps.extend(fc.travel_to(start_point))\n",
    "steps.extend(fc.squarewaveXY(start_point, direction, amplitude, line_spacing, periods, extra_half_period, extra_end_line))\n",
    "steps.append(fc.PlotAnnotation(point=start_point, label=\"start of wave 2\"))\n",
    "steps.append(fc.PlotAnnotation(label=\"extra half period\"))\n",
    "\n",
    "# wave 3\n",
    "start_point = fc.Point(x=10, y=30, z=0)\n",
    "extra_half_period = True\n",
    "extra_end_line = True\n",
    "# steps.extend([fc.Extruder(on=False), start_point, fc.Extruder(on=True)])\n",
    "steps.extend(fc.travel_to(start_point))\n",
    "steps.extend(fc.squarewaveXY(start_point, direction, amplitude, line_spacing, periods, extra_half_period, extra_end_line))\n",
    "steps.append(fc.PlotAnnotation(point=start_point, label=\"start of wave 3\"))\n",
    "steps.append(fc.PlotAnnotation(label=\"extra end-line\"))\n",
    "\n",
    "# wave 4\n",
    "start_point = fc.Point(x=10, y=40, z=0)\n",
    "direction_polar = tau/8\n",
    "# steps.extend([fc.Extruder(on=False), start_point, fc.Extruder(on=True)])\n",
    "steps.extend(fc.travel_to(start_point))\n",
    "steps.extend(fc.squarewaveXYpolar(start_point, direction_polar, amplitude, line_spacing, periods, extra_half_period, extra_end_line))\n",
    "steps.append(fc.PlotAnnotation(point=start_point, label=\"start of wave 4 (squarewaveXYpolar)\"))\n",
    "steps.append(fc.PlotAnnotation(label=\"wave in polar direction tau/8\"))\n",
    "\n",
    "# wave 5\n",
    "start_point = fc.Point(x=40, y=45, z=0)\n",
    "direction_polar = 0.75*tau\n",
    "tip_separation = 2\n",
    "extra_half_period = False\n",
    "# steps.extend([fc.Extruder(on=False), start_point, fc.Extruder(on=True)])\n",
    "steps.extend(fc.travel_to(start_point))\n",
    "steps.extend(fc.trianglewaveXYpolar(start_point, direction_polar, amplitude, tip_separation, periods, extra_half_period))\n",
    "steps.append(fc.PlotAnnotation(point=start_point, label=\"start of wave 5 (trianglewaveXYpolar)\"))\n",
    "\n",
    "# wave 5\n",
    "start_point = fc.Point(x=50, y=35, z=0)\n",
    "direction_polar = 0.75*tau\n",
    "period_lenth = 2\n",
    "segments_per_period = 16\n",
    "extra_half_period = False\n",
    "phase_shift = 0\n",
    "# steps.extend([fc.Extruder(on=False), start_point, fc.Extruder(on=True)])\n",
    "steps.extend(fc.travel_to(start_point))\n",
    "steps.extend(fc.sinewaveXYpolar(start_point, direction_polar, amplitude, period_lenth, periods, segments_per_period, extra_half_period, phase_shift))\n",
    "steps.append(fc.PlotAnnotation(point=start_point, label=\"start of wave 6 (sinewaveXYpolar)\"))\n",
    "\n",
    "fc.transform(steps, 'plot', fc.PlotControls(color_type='print_sequence', style='line'))"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### segmented line\n",
    "\n",
    "typically, a straight line is created with only start and end points. this means the shape of the line cannot be edited after creation. it is sometimes advantageous to be able to change the shape retrospectively. if the line is defined as a series of segments, all the points along the line can be edited after creation. the example below shows a straight line being modified based on each point\n",
    "\n",
    "the function segmented_line() allows a segmented line to be created easily based on a start point and end point"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "start_point = fc.Point(x=0, y=0, z=0)\n",
    "end_point = fc.Point(x=100, y=0, z=0.1)\n",
    "steps = fc.segmented_line(start_point, end_point, segments=15)\n",
    "for step in steps:\n",
    "    step.y = step.y + 20*sin(tau*step.x/200)\n",
    "for i in range(len(steps)): \n",
    "    steps.insert(i*2+1,fc.PlotAnnotation(label='')) # add blank PlotAnnotations at all points to highlight them in the plot \n",
    "steps.append(fc.PlotAnnotation(point=fc.Point(x=50, y=40,z=0), label='points along a segmented line can be modified after creation to form a curve'))\n",
    "fc.transform(steps, 'plot', fc.PlotControls(style='line'))"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## II. measurements from points\n",
    "\n",
    "functions:\n",
    "- distance\n",
    "- point_to_polar\n",
    "- angleXY_between_3_points"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pt1, pt2, pt3 = fc.Point(x=0, y=0, z=0), fc.Point(x=0, y=10, z=0), fc.Point(x=10, y=0, z=0)\n",
    "\n",
    "distance = fc.distance(pt1, pt2)\n",
    "print('distance between pt1 and pt2: ' + str(distance))\n",
    "\n",
    "polar_data = fc.point_to_polar(pt2, fc.Point(x=0, y=0, z=0))\n",
    "print(\"\\n'polar radius' of pt2 relative to x=0,y=0,z=0: \" + str(polar_data.radius))\n",
    "print(\"'polar angle' of pt2 relative to x=0,y=0,z=0: \" + str(polar_data.angle) + ' (radians: 0 to tau)')\n",
    "print(\"'polar angle' of pt2 relative to x=0,y=0,z=0: \" + str((polar_data.angle/tau)*360) + ' (degrees: 0 to 360)')\n",
    "# see the creation of a point from polar coordinates elsewhere in this notebook - fc.polar_to_point() \n",
    "\n",
    "angle = fc.angleXY_between_3_points(pt1, pt2, pt3)\n",
    "print('\\nangle between pt1-pt2-pt3: ' + str(angle) + ' (radians: -tau to tau)')\n",
    "print('angle between pt1-pt2-pt3: ' + str((angle/tau)*360) + ' (degrees: -360 to 360)')"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## III. move and copy points\n",
    "\n",
    "the move() function in FullControl allows moving and coping of a point, list of points, or a combined list of points and other ***state***-changing object\n",
    "\n",
    "the amount of movement is defined by FullControl's Vector object"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### move"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "vector = fc.Vector(x=0, y=0, z=0.5)\n",
    "\n",
    "start_point = fc.Point(x=0,y=0,z=0)\n",
    "print('start_point: ' + str(start_point))\n",
    "moved_start_point = fc.move(start_point, vector)\n",
    "print('moved_start_point: ' + str(moved_start_point))\n",
    "\n",
    "steps = fc.rectangleXY(start_point, 50, 20)\n",
    "print('\\noriginal points for a rectangle: ' + str(steps))\n",
    "steps = fc.move(steps, vector)\n",
    "print('moved rectangle: ' + str(steps))\n",
    "\n",
    "steps=[start_point,fc.Fan(speed_percent=90),moved_start_point]\n",
    "print('\\nlist with non-point object: ' + str(steps))\n",
    "print('moved list with non-point object ' + str(fc.move(steps,vector)))"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### copy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "vector = fc.Vector(x=0, y=0, z=0.5)\n",
    "start_point = fc.Point(x=0,y=0,z=0)\n",
    "steps = fc.rectangleXY(start_point, 50, 20)\n",
    "steps = fc.move(steps, vector,copy=True, copy_quantity=5)\n",
    "fc.transform(steps, 'plot', fc.PlotControls(style='line'))"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### move/copy (polar coordinates)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "array_centre = fc.Point(x=50,y=50,z=0)\n",
    "first_helix_centre = fc.Point(x=20, y=50, z=0)\n",
    "steps = fc.helixZ(first_helix_centre,10,10,0,5,0.5,100)\n",
    "steps = fc.move_polar(steps, array_centre, 0, tau/6, copy=True, copy_quantity=6)\n",
    "fc.transform(steps, 'plot', fc.PlotControls(style='line'))"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### reflect\n",
    "\n",
    "points can be reflected about a line that is defined by either two points (fc.reflectXY), or by one point and a polar angle (fc.reflectXYpolar)\n",
    "- polar angle convention:\n",
    "    - 0 = positive x direction\n",
    "    - 0.25*tau = positive y direction\n",
    "    - 0.5*tau = negative x direction\n",
    "    - 0.75*tau = negative y direction."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "steps = []\n",
    "\n",
    "pt1 = fc.Point(x=50, y=50, z=0)\n",
    "print('point before reflecting: \\n' + str(pt1))\n",
    "pt1_reflected = fc.reflectXY(pt1, fc.Point(x=0, y=0), fc.Point(x=1, y=0))\n",
    "print(\"point after reflecting about x-axis using 'reflectXY()': \\n\" + str(pt1_reflected))\n",
    "pt1_reflected = fc.reflectXYpolar(pt1, fc.Point(x=0, y=0), tau/4)\n",
    "print(\"point after reflecting about y-axis using 'reflect_polar()': \\n\" + str(pt1_reflected))"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### reflecting a list\n",
    "\n",
    "FullControl's reflect functions can only be used on individual points. reflecting lists of points is not simple because a reflected list of points must typically be printed in reverse order. otherwise, the nozzle would jump from the last point to the first point of the list before printing its reflection. if the list contained instructions halfway through to change ***state*** beyond a point (e.g. turn extrusion on/off), these instructions would affect different sections of the print path for the reflected and non-reflected lists since their sequences are reversed. therefore, FullControl allows the designer to reflect points only - it is up to the designer to iterate through a list of points, as demonstrated below. if ***state***-changing objects are included in the list, it is up to the designer to decide the appropriate location for them in the reflected list and to not attempt a reflectXY() function on them since they will not have xyz attributes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "steps = []\n",
    "steps.extend(fc.arcXY(fc.Point(x=50, y=50, z=0), 10, (5/8)*tau, tau/8, 16))\n",
    "steps.extend(fc.arcXY(fc.Point(x=80, y=55, z=0), 15, 0.75*tau, 0.5*tau, 16))\n",
    "steps.extend(fc.arcXY(fc.Point(x=80, y=65, z=0), 5, 0.25*tau, 0.5*tau, 16))\n",
    "steps.extend(fc.arcXY(fc.Point(x=80, y=55, z=0), 5, 0.25*tau, -0.5*tau, 16))\n",
    "steps.extend(fc.arcXY(fc.Point(x=60, y=60, z=0), 10, 0.75*tau, -tau/8, 16))\n",
    "\n",
    "steps_and_annotation = steps + [fc.PlotAnnotation(label='this geometry is reflected in next plot')]\n",
    "fc.transform(steps_and_annotation, 'plot', fc.PlotControls(color_type='print_sequence', style='line'))\n",
    "\n",
    "steps_reflected = []\n",
    "step_count = len(steps)\n",
    "for i in range(step_count):\n",
    "    # reflect about a line connecting the first point (steps[0]) and last point (steps[-1])\n",
    "    steps_reflected.append(fc.reflectXY(steps[(step_count-1)-i], steps[0], steps[-1]))\n",
    "steps.extend(steps_reflected)\n",
    "steps.extend([fc.PlotAnnotation(point = pt, label='') for pt in fc.segmented_line(fc.Point(x=43, y=43, z=0), fc.Point(x=52.5, y=52.5, z=0), 20)])\n",
    "# add some points to the plot to indicate the reflection line\n",
    "steps.append(fc.PlotAnnotation(point=steps[step_count], label='all points from the previous plot were reflected and added to the path (in reverse order)'))\n",
    "fc.transform(steps, 'plot', fc.PlotControls(color_type='print_sequence', style='line'))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.11"
  },
  "vscode": {
   "interpreter": {
    "hash": "2b13a99eb0d91dd901c683fa32c6210ac0c6779bab056ce7c570b3b366dfe237"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
